#
# ComicViewer.py
# (c) 2008 Will Baker.
#

from PyQt4.QtCore import Qt, QObject, SIGNAL, SLOT, QPoint, QTimer, QRect
from PyQt4.QtGui import QWidget, QPainter, QAction, QKeySequence

from model import ComicLoader

from PageRenderer import PageRenderer
from ComicViewOptions import ComicViewOptions

class ComicViewer(QWidget):
    """
    A Window in which a Comic is displayed.
    """
    def __init__( self, comic, main_window, flags=0 ):
        QWidget.__init__( self, main_window, flags )
        self.comic = comic
        self.main_window = main_window
        self.pages = {}
        self.page = 0
        self.comic_loader = ComicLoader( self )
        self.view_options = ComicViewOptions()
        self.refine_timer = QTimer( self )
        
        QObject.connect( self.refine_timer, SIGNAL("timeout()"), self.on_refine )
        
        action = QAction( "Previous Page", self )
        action.setShortcut( QKeySequence("Left") )
        QObject.connect( action, SIGNAL("triggered()"), self.on_previous_page )
        self.addAction( action )
        
        action = QAction( "Next Page", self )
        action.setShortcut( QKeySequence("Right") )
        QObject.connect( action, SIGNAL("triggered()"), self.on_next_page )
        self.addAction( action )
        
        action = QAction( "Previous Item", self )
        action.setShortcut( QKeySequence("Up") )
        QObject.connect( action, SIGNAL("triggered()"), self.on_previous_item )
        self.addAction( action )
        
        action = QAction( "Next Item", self )
        action.setShortcut( QKeySequence("Down") )
        QObject.connect( action, SIGNAL("triggered()"), self.on_next_item )
        self.addAction( action )
        
        action = QAction( "Scale", self )
        action.setShortcut( QKeySequence("z") )
        QObject.connect( action, SIGNAL("triggered()"), self.on_scale )
        self.addAction( action )
        
        action = QAction( "Rotate", self )
        action.setShortcut( QKeySequence("r") )
        QObject.connect( action, SIGNAL("triggered()"), self.on_rotate )
        self.addAction( action )
        
        action = QAction( "Fullscreen", self )
        action.setShortcut( QKeySequence("f") )
        QObject.connect( action, SIGNAL("triggered()"), self.on_fullscreen )
        self.addAction( action )
        
        action = QAction( "Double Page", self )
        action.setShortcut( QKeySequence("d") )
        QObject.connect( action, SIGNAL("triggered()"), self.on_double )
        self.addAction( action )
        
        action = QAction( "Close", self )
        action.setShortcut( QKeySequence("Escape") )
        QObject.connect( action, SIGNAL("triggered()"), self, SLOT("close()") )
        self.addAction( action )
        
        self.setWindowTitle( comic.name )
        self.setMouseTracking( True )
        self.setFocusPolicy( Qt.ClickFocus )
        self.setAttribute( Qt.WA_DeleteOnClose, True )
        
        self.resize( 500, 600 )
        self.comic_loader.load_all_pages( self.comic )
        self.start_refine_timer()
        
    def __del__( self ):
        self.clear()
        
    def set_comic( self, comic ):
        """
        Set the Comic.
        """
        self.page = 0
        self.pages = {}
        self.clear()
        self.comic = comic
        self.comic_loader = ComicLoader( self )
        self.comic_loader.load_all_pages( self.comic )
        self.start_refine_timer()
        self.update()
        
    def set_page( self, page ):
        """
        Set the current page.
        """
        self.page = page
        self.update()
         
    def on_page_count_loaded( self ):
        """
        Handle the page count being loaded. This is generally called from a JobThread,
        not the main thread.
        """
        self.update()
        
    def on_page_loaded( self, page ):
        """
        Handle a page being loaded. This is generally called from a JobThread,
        not the main thread.
        """
        self.pages[page.index] = page
        self.update()
        
    def clear( self ):
        """
        Stop loading images.
        """
        self.comic_loader.stop()
        
    def on_previous_page( self ):
        """
        Go to the previous page.
        """
        if self.page > 0:
            self.page -= 1
            self.start_refine_timer()
            self.update()
        
    def on_next_page( self ):
        """
        Go to the next page.
        """
        if self.page < self.comic.page_count-1:
            self.page += 1
            self.start_refine_timer()
            self.update()
            
    def on_previous_item( self ):
        """
        Request the previous item in the results set.
        """
        self.emit( SIGNAL("previous_item"), self )
        
    def on_next_item( self ):
        """
        Request the next item in the results set.
        """
        self.emit( SIGNAL("next_item"), self )
            
    def on_scale( self ):
        """
        Toggle the scale mode.
        """
        self.view_options.toggle_scale()
        self.start_refine_timer()
        self.update()
        
    def on_rotate( self ):
        """
        Toggle the rotation mode.
        """
        self.view_options.toggle_rotation()
        self.start_refine_timer()
        self.update()
        
    def on_fullscreen( self ):
        """
        Toggle fullscreen mode.
        """
        self.setWindowState( self.windowState() ^ Qt.WindowFullScreen )
        if self.isFullScreen():
            self.setCursor( Qt.BlankCursor )
        else:
            self.setCursor( Qt.ArrowCursor )
        self.start_refine_timer()
        self.update()
        
    def on_double( self ):
        """
        Toggle double page mode.
        """
        self.view_options.toggle_double()
        if self.page == 0:
            self.on_next_page()
        self.start_refine_timer()
        self.update()
        
    def on_refine( self ):
        """
        Toggle the scaling of the image to be smooth.
        """
        self.view_options.refine = True
        self.update()
    
    def start_refine_timer( self ):
        """
        Start the refinement timer. This toggles the scaling of the image to be fast
        and then starts the timer.
        """
        self.view_options.refine = False
        self.refine_timer.start( 500 )
        
    def draw_progress_bar( self, painter ):
        """
        Draw the loading progress bar.
        """
        progress = QRect( 0, 0, 100, 5 )
        progress.translate( self.rect().center() + QPoint(-50, 10) )
        painter.setOpacity( 0.2 )
        painter.fillRect( progress, Qt.white )
        
        if self.comic.page_count > 0:
            progress.setWidth( int(100 * len(self.pages) / self.comic.page_count) )
            painter.setOpacity( 0.3 )
            painter.fillRect( progress, Qt.white )
            painter.fillRect( progress.x() + int(100*(self.page+1)/self.comic.page_count), progress.y(), 1, 5, Qt.white )
        
    def mouseMoveEvent( self, e ):
        """
        Handle a mouse movement event.
        """
        x = -float(e.pos().x()) / self.width() + 0.5
        y = -float(e.pos().y()) / self.height() + 0.5
                
        self.view_options.scroll.setX( x )
        self.view_options.scroll.setY( y )
        
        self.start_refine_timer()
        self.update()
        
    def resizeEvent( self, e ):
        """
        Handle the window resizing.
        """
        self.start_refine_timer()
        
    def paintEvent( self, e ):
        """
        Repaint this ComicViewer.
        """        
        renderer = PageRenderer( self.size(), self.view_options )
        if self.view_options.double and self.page-1 in self.pages:
            renderer.push( self.pages[self.page-1] )
        if self.page in self.pages:
            renderer.push( self.pages[self.page] )
            
        painter = QPainter( self )
        painter.fillRect( self.rect(), Qt.black )
        if len(renderer.pages) == 0:
            painter.setPen( Qt.white )
            painter.drawText( self.rect(), Qt.AlignCenter, "Loading..." )
            self.draw_progress_bar( painter )
        else:
            renderer.prepare()
            renderer.render( painter )     
        painter.end()

    def closeEvent( self, e ):
        """
        Handle the window being closed.
        """
        self.emit( SIGNAL("comic_closed"), self.comic, self.page )
        self.clear()
